package com.wenda.admin.core;

import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


import com.wenda.admin.config.ApplicationContextUtil;
import com.wenda.admin.entity.TbFlow;
import com.wenda.admin.mapper.FlowMapper;
import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
import jpcap.NetworkInterfaceAddress;
import jpcap.PacketReceiver;
import jpcap.packet.ARPPacket;
import jpcap.packet.EthernetPacket;
import jpcap.packet.ICMPPacket;
import jpcap.packet.IPPacket;
import jpcap.packet.Packet;
import jpcap.packet.TCPPacket;
import jpcap.packet.UDPPacket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CatchDataPkg implements PacketReceiver {
    public static volatile boolean sw = false;
    public static NetworkInterface dev;
    private static JpcapCaptor jpcap = null;
    //初始化抓包网卡
    public static void start(NetworkInterface deviceName) throws IOException {

        jpcap = JpcapCaptor.openDevice(deviceName, 2000, false, 1);
        //过滤代码 可以协议 端口 IP 组合
        //jpcap.setFilter("ip and tcp and (dst host 10.255.0.13 and dst port 12388)",true);
        //jpcap.setFilter("udp",true);
        jpcap.loopPacket(-1, new CatchDataPkg());
    }

    public static void stop(){
        if(jpcap != null){
            try{
                jpcap.close();
            }catch (Exception e){
                jpcap = null;
                e.printStackTrace();
            }

        }
    }
 
    @Override
    public void receivePacket(Packet packet) {
        FlowMapper flowMapper = ApplicationContextUtil.getBean(FlowMapper.class);
        TbFlow flow = new TbFlow();
        flow.setCreateTime(new Date());

        //封装抓包获取到数据
        Map<String, Object> dataMap = new HashMap<>();
        /* 分析协议类型 */  
        if (packet.getClass().equals(IPPacket.class)) {
            System.out.println("协议类型 ：IP协议"); 
            dataMap.put("protocolType", "IP");  //协议类型
            IPPacket ipPacket = (IPPacket) packet;

            byte[] iph = ipPacket.option;
            String iphstr = new String(iph);
            flow.setProtocol("IP");
            flow.setStartIp(ipPacket.src_ip.getHostAddress());
            flow.setToIp(ipPacket.dst_ip.getHostAddress());
            if(ipPacket.data != null){
                flow.setContent(new String(ipPacket.data));
            }
            flowMapper.insert(flow);
            System.out.println(iphstr);
        }  
 
        if (packet.getClass().equals(ARPPacket.class)) {  
            readHead(packet, dataMap);  
            dataMap.put("protocolType", "ARP");  //协议类型
            try {  
                ARPPacket arpPacket = (ARPPacket) packet;  
 
                dataMap.put("captureLength", arpPacket.caplen); //数据包长度
 
                dataMap.put("timestamp", arpPacket.sec); //时间戳(秒)
 
                dataMap.put("sendMacAdrr", arpPacket.getSenderHardwareAddress()); //源网卡Mac地址
 
                dataMap.put("sendIPAdrr", arpPacket.getSenderProtocolAddress()); //源IP地址
 
                dataMap.put("targetMacAdrr", arpPacket.getTargetHardwareAddress()); //目的网卡MAC地址
 
                dataMap.put("targetIPAdrr", arpPacket.getTargetProtocolAddress()); //目的IP地址
                flow.setProtocol("ARP");
                flow.setStartIp(arpPacket.getSenderProtocolAddress().toString().replace("/",""));
                flow.setToIp(arpPacket.getTargetProtocolAddress().toString().replace("/",""));
                if(arpPacket.data != null){
                    flow.setContent(new String(arpPacket.data));
                }
                flowMapper.insert(flow);
                readData(packet, dataMap);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        } else if (packet.getClass().equals(UDPPacket.class)) {  
            readHead(packet, dataMap);  
            dataMap.put("protocolType", "UDP");  //协议类型
            try {  
                UDPPacket udpPacket = (UDPPacket) packet;

                dataMap.put("captureLength", udpPacket.caplen); //数据包长度
 
                dataMap.put("timestamp", udpPacket.sec); //时间戳(秒)
 
                dataMap.put("sendIPAdrr", udpPacket.src_ip); //源IP地址
 
                //dataMap.put("srcMac", udpPacket.);
 
                dataMap.put("sendPort", udpPacket.src_port); //源端口
 
                dataMap.put("targetIPAdrr", udpPacket.dst_ip); //目的IP地址
 
                dataMap.put("targetPort", udpPacket.dst_port); //目的端口
 
                //dataMap.put("sequence", udpPacket.sequence); //sequence udp not
 
                //dataMap.put("window", udpPacket.window); //window udp not
 
                //dataMap.put("ackNum", udpPacket.ack_num); //ack_num udp not
 
                dataMap.put("timeToLive", udpPacket.hop_limit); //生存时间
 
                dataMap.put("protocolVersion", udpPacket.version); //版本信息
 
                System.out.println("版本" + udpPacket.version); //版本信息
 
                EthernetPacket datalink = (EthernetPacket) udpPacket.datalink;
                StringBuffer srcMacStr = new StringBuffer(); 
                int count = 1;
                for (byte b : datalink.src_mac) {  
                    srcMacStr.append(Integer.toHexString(b & 0xff));
                    if(count++ != datalink.src_mac.length) 
                        srcMacStr.append(":");
                }
 
                dataMap.put("sendMacAdrr", srcMacStr);  //源mac地址
 
                StringBuffer dstMacStr = new StringBuffer();  
                int count2 = 1;    
                for (byte b : datalink.dst_mac) {  
                    dstMacStr.append(Integer.toHexString(b & 0xff));
                    if(count2++ != datalink.dst_mac.length) 
                        dstMacStr.append(":");
                }
 
                dataMap.put("targetMacAdrr", dstMacStr); //目标mac地址
 
                //udp not flag
                flow.setProtocol("UDP");
                flow.setStartIp(udpPacket.src_ip.getHostAddress());
                flow.setStartPort(udpPacket.src_port+"");
                flow.setToIp(udpPacket.dst_ip.getHostAddress());
                flow.setToPort(udpPacket.dst_port + "");
                if(udpPacket.data != null){
                    flow.setContent(new String(udpPacket.data));
                }
                flowMapper.insert(flow);
                readData(packet, dataMap);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        } else if (packet.getClass().equals(TCPPacket.class)) {  
            readHead(packet, dataMap);  
            //System.out.println("协议类型 ：TCP协议");
            dataMap.put("protocolType", "TCP");  //协议类型
            try {  
                TCPPacket tcpPacket = (TCPPacket) packet; 
 
                dataMap.put("captureLength", tcpPacket.caplen); //数据包长度
 
                dataMap.put("timestamp", tcpPacket.sec); //时间戳(秒)
 
                dataMap.put("sendIPAdrr", tcpPacket.src_ip); //源IP地址
 
                dataMap.put("sendPort", tcpPacket.src_port); //源端口
 
                dataMap.put("targetIPAdrr", tcpPacket.dst_ip); //目的IP地址
 
                dataMap.put("targetPort", tcpPacket.dst_port); //目的端口
 
                dataMap.put("sequence", tcpPacket.sequence); //sequence
 
                dataMap.put("window", tcpPacket.window); //window
 
                dataMap.put("ackNum", tcpPacket.ack_num); //ack_num
 
                dataMap.put("timeToLive", tcpPacket.hop_limit); //生存时间
 
                dataMap.put("protocolVersion", tcpPacket.version); //版本信息
 
                EthernetPacket datalink = (EthernetPacket) tcpPacket.datalink;
                StringBuffer srcMacStr = new StringBuffer(); 
                int count = 1;
                for (byte b : datalink.src_mac) {  
                    srcMacStr.append(Integer.toHexString(b & 0xff));
                    if(count++ != datalink.src_mac.length) 
                        srcMacStr.append(":");
                }
 
                dataMap.put("sendMacAdrr", srcMacStr);  //源mac地址
 
                StringBuffer dstMacStr = new StringBuffer();  
                int count2 = 1;    
                for (byte b : datalink.dst_mac) {  
                    dstMacStr.append(Integer.toHexString(b & 0xff));
                    if(count2++ != datalink.dst_mac.length) 
                        dstMacStr.append(":");
                }
 
                dataMap.put("targetMacAdrr", dstMacStr); //目标mac地址
 
                //flag
                dataMap.put("fin", tcpPacket.fin); //fin
 
                dataMap.put("syn", tcpPacket.fin); //syn
 
                dataMap.put("rst", tcpPacket.rst); //rst
 
                dataMap.put("ack", tcpPacket.ack); //ack
 
                dataMap.put("urg", tcpPacket.urg); //urg
                flow.setProtocol("TCP");
                flow.setStartIp(tcpPacket.src_ip.getHostAddress());
                flow.setStartPort(tcpPacket.src_port+"");
                flow.setToIp(tcpPacket.dst_ip.getHostAddress());
                flow.setToPort(tcpPacket.dst_port + "");
                if(tcpPacket.data != null){
                    flow.setContent(new String(tcpPacket.data));
                }
                flowMapper.insert(flow);
                readData(packet, dataMap);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        } else if (packet.getClass().equals(ICMPPacket.class))  
            {  
              readHead(packet, dataMap);  
              ICMPPacket icmpPacket = (ICMPPacket) packet;
 
              dataMap.put("protocolType", "ICMP");  //协议类型
 
              dataMap.put("captureLength", icmpPacket.caplen); //数据包长度
 
              dataMap.put("timestamp", icmpPacket.sec); //时间戳
 
              dataMap.put("sendIPAdrr", icmpPacket.src_ip); //源IP地址
 
              //dataMap.put("srcPort", icmpPacket.); //源端口
 
              dataMap.put("targetIPAdrr", icmpPacket.dst_ip); //目的IP地址
 
              dataMap.put("protocolVersion", icmpPacket.version); //版本信息
 
              dataMap.put("timeToLive", icmpPacket.hop_limit); //生存时间
 
              //dataMap.put("dstPort", icmpPacket.dst_port); //目的端口
                flow.setProtocol("ICMP");
                flow.setStartIp(icmpPacket.src_ip.getHostAddress());
                flow.setToIp(icmpPacket.dst_ip.getHostAddress());
                if(icmpPacket.data != null){
                    flow.setContent(new String(icmpPacket.data));
                }
                flowMapper.insert(flow);
              readData(packet, dataMap);  
        }
        Iterator<Map.Entry<String, Object>> it = dataMap.entrySet().iterator();
 
         while (it.hasNext()) {
               Map.Entry<String, Object> entry = it.next();
               System.out.println("[key]=" + entry.getKey() + "       [value]=" + entry.getValue());
         }
         System.out.println("*******************************************");
    }
 
    /**
     * IP数据报报文头
     * @param packet
     */
    public void readHead(Packet packet, Map<String, Object> dataMap){  
        byte[] l = packet.header;  
        /*StringBuffer sb = new StringBuffer();
        for (int i = 0; i < l.length; i++) {  
            int m = 0;  
            m = l[i];  
            m = m << 24;  
            m = m >>> 24;  
            sb.append(Integer.toHexString(m));
        } 
        dataMap.put("messageHead", sb);*/ //报文头
        int d = l.length; 
        dataMap.put("headLen", (d * 8)); //首部长度
    }  
 
    /**
     * IP数据报文数据
     * @param packet
     */
    public void readData(Packet packet, Map<String, Object> dataMap){  
        byte[] k = packet.data;  
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < k.length; i++) {  
            try {  
                sb.append(new String(k, "utf-8"));  
            } catch (UnsupportedEncodingException e) {  
            }  
        }
 
        String s = " " + packet.getClass();
        dataMap.put("messageType", s.substring(s.lastIndexOf(".") + 1)); //报文类型
    }
 
    /**
     * 把抓到的数据包存到磁盘 （此方法暂时无用）
     * @param result
     */
    private void write(String result) {  
        try {  
            FileOutputStream fis = new FileOutputStream("D:\\result.txt",true);  
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fis));  
            writer.write(result);  
            writer.flush();  
            writer.close();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }
}